#include "../pubsubclient.h"
using namespace pubsub;
PubSubClient::PubSubClient(EventLoop *loop, const InetAddress &listenAddr)
    : _client(loop, listenAddr)
{
    _client.setConnectionCallback(
        std::bind(&PubSubClient::onConnection, this, _1));
    _client.setMessageCallback(
        std::bind(&PubSubClient::onMessage, this, _1, _2, _3));
}

void PubSubClient::start()
{
    _client.connect();
}
void PubSubClient::stop()
{
    _client.disconnect();
}

bool PubSubClient::connected() const
{
    return _conn && _conn->connected();
}

void PubSubClient::setConnectionCallback(const ConnectionCallback &cb)
{
    _connectionCallback = cb;
}

bool PubSubClient::subscribe(const string &topic, const SubscribeCallback &cb)
{
    string message = "sub " + topic + "\r\n";
    _subscribeCallback = cb;
    return send(message);
}
void PubSubClient::unsubscribe(const string &topic)
{
    string message = "unsub " + topic + "\r\n";
    send(message);
}
bool PubSubClient::publish(const string &topic, const string &content)
{
    string message = "pub " + topic + "\r\n" + content + "\r\n";
    return send(message);
}
void PubSubClient::onConnection(const TcpConnectionPtr &conn)
{
    if (conn->connected())
    {
        _conn = conn;
    }
    else
    {
        _conn.reset();
    }
    
    if (_connectionCallback)
    {
        _connectionCallback(this);
    }
}
void PubSubClient::onMessage(const TcpConnectionPtr &conn,
                             Buffer *buff,
                             Timestamp receiveTime)
{
    ParseResult result = kSuccess;
    while (result == kSuccess)
    {
        string cmd;
        string topic;
        string content;
        result = parseMessage(buff,&cmd, &topic, &content);
        if (result == kSuccess)
        {
            if (cmd == "pub" && _subscribeCallback)
            {
                _subscribeCallback(topic, content, receiveTime);
            }
        }
        else if (result == kError)
        {
            _conn->shutdown();
        }
    }
}
bool PubSubClient::send(const string &message)
{
    bool succeed = false;
    if (_conn && _conn->connected())
    {
        _conn->send(message);
        succeed = true;
    }
    return succeed;
}